import {ContactShadows, Environment, Grid, OrbitControls, Sky, useCursor} from '@react-three/drei'
import {Avatar} from './Avatar.jsx'
import {useAtom} from 'jotai'
import {charactersAtom, mapAtom, socket, userAtom} from './SocketManager.jsx'
import React, {Suspense, useEffect, useRef, useState} from 'react'
import * as THREE from 'three'
import {GoodsItem} from './GoodsItem.jsx'
import {useThree} from '@react-three/fiber'
import {useGrid} from '../hooks/useGrid.jsx'
import {buildModeAtom, draggedItemAtom, draggedItemRotationAtom, shopModeAtom} from './UI.jsx'
import {CAMERA_SIZE} from '../App.jsx'
import {Shop} from './Shop.jsx'

export const Experience = () => {
  // 是否是创建房间模式
  // const [buildMode, setBuildMode] = useState(true)
  const [buildMode, setBuildMode] = useAtom(buildModeAtom)
  // 是否为购物模式：添加新物品
  const [shopMode, setShopMode] = useAtom(shopModeAtom)

  const [characters, setCharacters] = useAtom(charactersAtom)
  const [map, setMap] = useAtom(mapAtom)

  // 房间物品集合
  const [items, setItems] = useState(map.items)

  // console.log('map--- ', map)

  const [onFloor, setOnFloor] = useState(false)
  useCursor(onFloor)

  const {v3ToGrid, gridToV3} = useGrid()
  const scene = useThree((state) => state.scene)
  const [user, setUser] = useAtom(userAtom)

  /**
   * 鼠标点击地板时事件
   * @param e 当前点击位置 v3
   */
  const onClickPlaneHandler = (e) => {
    // 构建房间模式下
    if (buildMode) {
      // 移动物品
      onGoodsItemMoveHandler(e)
    } else {
      // 移动人员
      onCharacterMoveHandler(e)
    }
  }

  /**
   * 鼠标在地板上移动触发：更新当前移动物品坐标
   * @param e 鼠标在地板上移动时坐标 v3
   */
  const onPointerMovePlaneHandler = (e) => {
    if (!buildMode) return
    // 获取新的位置，转换为网格坐标
    const newPos = v3ToGrid(e.point)
    // console.log('🚀🚀🚀', newPos)
    // 如果拖拽位置draggedPos不存在 或者 当前鼠标移动位置newPos不等于拖拽位置draggedPos
    if (!draggedPos ||
      newPos[0] !== draggedPos[0] ||
      newPos[1] !== draggedPos[1]
    ) {
      // 存储当前鼠标移动位置newPos到拖拽位置
      setDraggedPos(newPos)

      // 通知服务端有拖拽
      // socket.emit('drag-item', newPos)
    }
  }

  /**
   * 鼠标在地板上点击 => 移动物品
   * @param e
   */
  const onGoodsItemMoveHandler = (e) => {
    // 当前存在拖拽物品
    if (draggedItem !== null) {
      // 当前位置是否放置物品
      if (canDrag) {
        setItems((prev) => {
          const newItems = [...prev]
          // 删除原有的没用的临时属性tmp
          delete newItems[draggedItem].tmp
          // 更新当前位置到被拖拽物体
          newItems[draggedItem].position = v3ToGrid(e.point)
          // 更新旋转角度到被拖拽物体
          newItems[draggedItem].rotation = draggedItemRotation
          return newItems
        })
      }
      // 清空被拖拽物品，即代表拖拽结束
      setDraggedItem(null)
    }

  }

  /**
   * 移动人员
   * @param e 当前鼠标点击位置 v3
   */
  const onCharacterMoveHandler = (e) => {
    // 初始版移动逻辑
    // socket.emit('move', [e.point.x, 0, e.point.z])

    const character = scene.getObjectByName(`character-${user}`)
    if (!character) return

    const from = v3ToGrid(character.position)
    const to = v3ToGrid(e.point)
    // console.log(from, to)
    socket.emit('move', from, to)

  }

  /**
   * 选择商店物品时出发
   * @param item 被选择物品
   */
  const onShopItemSelectedHandler = (item) => {
    // 关闭商店
    setShopMode(false)

    // 添加被选择物品到items中
    setItems((prev) => [
      ...prev,
      {
        ...item,
        position: [0, 0],
        tmp: true
      }
    ])

    // 设置当前拖拽对象为item最后一个:即新添加的商店物品
    setDraggedItem(items.length)
    // 重置当前拖拽对象的旋转角度为0
    setDraggedItemRotation(0)
  }

  // 记录当前拖拽物品索引
  // const [draggedItem, setDraggedItem] = useState(null)
  const [draggedItem, setDraggedItem] = useAtom(draggedItemAtom)
  // 记录当前拖拽物品旋转角度
  const [draggedItemRotation, setDraggedItemRotation] = useAtom(
    draggedItemRotationAtom
  )
  // 记录拖拽位置
  const [draggedPos, setDraggedPos] = useState(null)
  // 物品是否可以拖拽到当前位置，可以物品显示绿色，不可以显示红色
  const [canDrag, setCanDrag] = useState(false)
  // console.log('🚀🚀🚀', draggedPos)

  /**
   * 物体被移动时触发，目的设置当前移动物品是否可以被放置在当前位置上
   */
  useEffect(() => {
    if (!draggedItem) return
    const item = items[draggedItem]
    const {size, position, rotation, walkable, wall} = item

    // 优化拖拽模式下物品旋转角度需要从当前拖拽角度取
    // const width = (rotation === 1 || rotation === 3) ? size[1] : size[0]
    // const height = (rotation === 1 || rotation === 3) ? size[0] : size[1]
    const width = (draggedItemRotation === 1 || draggedItemRotation === 3) ? size[1] : size[0]
    const height = (draggedItemRotation === 1 || draggedItemRotation === 3) ? size[0] : size[1]

    let droppable = true
    const {girdSize, girdSpace} = map
    // 校验物品是否在地板范围内
    if (draggedPos[0] < 0 ||
      draggedPos[0] + width > girdSize[0] * girdSpace) {
      droppable = false
    }
    if (draggedPos[1] < 0 ||
      draggedPos[1] + height > girdSize[1] * girdSpace) {
      droppable = false
    }

    // 校验是否碰撞其他物品
    if (!walkable && !wall) {
      items.forEach((other, idx) => {
        // 排除自身
        if (idx === draggedItem) {
          return
        }

        // 排除其他是地板或者墙
        if (other.walkable || other.wall) {
          return
        }

        // 是否重叠
        const otherW = other.rotation === 1 || other.rotation === 3 ? other.size[1] : other.size[0]
        const otherH = other.rotation === 1 || other.rotation === 3 ? other.size[0] : other.size[1]
        // 简版的重叠校验
        if (
          draggedPos[0] < other.position[0] + otherW &&
          draggedPos[0] + width > other.position[0] &&
          draggedPos[1] < other.position[1] + otherH &&
          draggedPos[1] + height > other.position[1]
        ) {
          droppable = false
        }
      })
    }

    setCanDrag(droppable)

  }, [draggedPos, draggedItem, items, draggedItemRotation])

  // 定义相机控制器
  const controls = useRef()
  const state = useThree(state => state)

  // 监控拖拽物体，如果为空，更新items为排除有tmp属性的item
  // 从商店拖拽物体：在重叠下点击放置以及取消放置时物品放置在原点，
  // 正常情况下应该排除掉，用户需要的话重新从商店中添加
  useEffect(() => {
    if (draggedItem === null) {
      setItems((prev) => prev.filter((item) => !item.tmp))
    }
  }, [draggedItem])

  // 构建模式下
  useEffect(() => {
    if (buildMode) {
      // 构建模式下设置物品集合信息
      setItems(map?.items || [])
      // 构建模式下，相机位置设置为初始值
      state.camera.position.set(
        CAMERA_SIZE, CAMERA_SIZE, CAMERA_SIZE
      )
      // 控制器设置目标点位为原点
      controls.current.target.set(0, 0, 0)
    } else {
      // 发送消息到服务端，更新物品信息
      socket.emit('items-update', items)
    }
  }, [buildMode])

  // 商城模式下
  useEffect(() => {
    if (shopMode) {
      state.camera.position.set(
        0, CAMERA_SIZE * 0.5, CAMERA_SIZE
      )
      // 控制器设置目标点位为原点
      controls.current.target.set(0, 0, 0)
    } else {
      state.camera.position.set(
        CAMERA_SIZE, CAMERA_SIZE, CAMERA_SIZE
      )
      // 控制器设置目标点位为原点
      controls.current.target.set(0, 0, 0)
    }
  }, [shopMode])

  return (
    <>
      {/* enabled={!shopMode} 在商城模式下，禁用鼠标控制器 */}
      <OrbitControls
        ref={controls}
        minDistance={5}
        maxDistance={20}
        minPolarAngle={0}
        maxPolarAngle={Math.PI * 0.5}
        screenSpacePanning={false}
        enableZoom={!shopMode}
      />
      {/* <mesh>
        <boxGeometry />
        <meshNormalMaterial />
      </mesh> */}

      <Sky
        distance={450000}
        sunPosition={[5, 8, 20]}
        inclination={0}
        azimuth={0.25}
        rayleigh={0.1}
      />
      <Environment files={'/textures/venice_sunset_1k.hdr'}/>

      <ambientLight intensity={0.1}/>

      {/* 添加定向光 */}
      <directionalLight
        position={[4, 4, -4]}
        castShadow
        intensity={0.35}
        shadow-mapSize={[1024, 1024]}
      >
        <orthographicCamera
          attach={'shadow-camera'}
          args={[-10, 10, 10, -10]}
          far={20 + 2}
        />
      </directionalLight>

      {/* 构建模式下显示网格 */}
      {buildMode && !shopMode && <Grid infiniteGrid fadeDistance={50} fadeStrength={5}/>}

      {/* 商店模式 */}
      {
        shopMode &&
        <Shop
          onShopItemSelected={onShopItemSelectedHandler}
        />
      }

      {/* <ContactShadows blur={2}/> */}
      {/* 房间地板 */}
      {
        !shopMode &&
        <mesh rotation-x={-Math.PI * 0.5}
              position-y={-0.001}
              onClick={onClickPlaneHandler}
              onPointerEnter={() => setOnFloor(true)}
              onPointerLeave={() => setOnFloor(false)}
              onPointerMove={onPointerMovePlaneHandler}
              position-x={map.girdSize[0] * 0.5}
              position-z={map.girdSize[1] * 0.5}
              receiveShadow
        >
          <planeGeometry args={map.girdSize}/>
          <meshStandardMaterial color="#f0f0f0"/>
        </mesh>
      }

      {/* <GoodsItem name={"chair"} /> */}
      {/* <GoodsItem name={"table"} /> */}
      {/* <GoodsItem name={"plant"} /> */}
      {/* <GoodsItem name={"desk"} /> */}
      {
        !shopMode &&
        (buildMode ? items : map.items).map((item, idx) => (
          <GoodsItem key={`${item.name}-${idx}`}
                     item={item}
                     onClick={() => {
                       if (buildMode) {
                         setDraggedItem((prev) => (prev === null ? idx : prev))
                         setDraggedItemRotation(item.rotation || 0)
                       }
                     }}
                     isDragging={draggedItem === idx}
                     draggedPos={draggedPos}
                     draggedRotation={draggedItemRotation}
                     canDrag={canDrag}
          />
        ))
      }


      {
        !buildMode &&
        characters.map(c => (
          <Suspense key={c.id}>
          <Avatar
            id={c.id}
            position={gridToV3(c.position)}
            hairColor={c.hairColor}
            topColor={c.topColor}
            bottomColor={c.bottomColor}
            avatarUrl={c.avatarUrl}
          />
          </Suspense>
        ))
      }
      {/* <AnimatedWoman />
      <AnimatedWoman position-x={1} hairColor='red' topColor='blue' /> */}
    </>
  )
}
